package com.gzc.just.play.last.war.sceneserver.effect;

import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectCamp;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectType;
import com.gzc.just.play.last.war.sceneserver.gameobject.unit.GameUnit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

/**
 * StatusEffectManager 单元测试 - 测试状态效果管理器的核心功能
 * 覆盖效果的应用、移除、更新、过期和查询功能
 */
@DisplayName("状态效果管理器单元测试")
class StatusEffectManagerTest {

    @Mock
    private GameUnit mockOwner;

    private StatusEffectManager effectManager;
    private StatusEffect testEffect;
    private StatusEffect testEffect2;
    
    /**
     * 测试用的 StatusEffect 实现类
     */
    static class TestStatusEffect extends StatusEffect {
        private boolean periodicDamage;
        private boolean stackable;
        
        public TestStatusEffect(String id, StatusType statusType, GameUnit target, 
                                long duration, GameUnit source, int level, double power, 
                                boolean stackable, boolean periodicDamage) {
            super(id, statusType, target, duration, source, level, power);
            this.stackable = stackable;
            this.periodicDamage = periodicDamage;
        }
        
        @Override
        public void onApply() {
            // 测试中不执行实际操作
        }
        
        @Override
        public void onRemove() {
            // 测试中不执行实际操作
        }
        
        @Override
        public void onUpdate(long currentTime, long deltaTime) {
            // 测试中不执行实际操作
        }
        
        @Override
        public void onRefresh() {
            // 测试中不执行实际操作
        }
        
        @Override
        public boolean shouldRemove() {
            return System.currentTimeMillis() >= getEndTime();
        }
        
        public boolean isPeriodicDamage() {
            return periodicDamage;
        }
        
        public boolean isStackable() {
            return stackable;
        }
        
        public long getRemainingDuration() {
            long now = System.currentTimeMillis();
            return Math.max(0, getEndTime() - now);
        }
        
        public float getDamageAmount() {
            return periodicDamage ? (float) getPower() : 0;
        }
    }

    /**
     * 测试用的 GameUnit 实现类
     */
    static class TestGameUnit extends GameUnit {
        public TestGameUnit(long objectId, GameObjectType objectType, GameObjectCamp camp,
                           int maxHealth, int maxMana, double attack, double defense, double speed) {
            super(objectId, objectType, camp, maxHealth, maxMana, attack, defense, speed);
        }

        @Override
        protected void checkDeadState() {
        }
    }

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        
        // 使用真实的 GameUnit 实例进行测试
        GameUnit owner = new TestGameUnit(1, GameObjectType.HERO, GameObjectCamp.TEAM_1, 1000, 500, 100, 50, 100);
        owner.initialize();
        effectManager = new StatusEffectManager(owner);
        
        // 创建测试用的状态效果
        testEffect = new TestStatusEffect("effect1", StatusType.POWER, owner, 1000, null, 1, 1.2, false, false);
        testEffect2 = new TestStatusEffect("effect2", StatusType.FRAGILE, owner, 2000, null, 1, 0.8, false, false);
    }

    // ========== 效果应用 ==========

    @Test
    @DisplayName("测试1: 应用状态效果")
    void testApplyEffect() {
        effectManager.applyEffect(testEffect);
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(1, activeEffects.size());
        assertEquals(testEffect, activeEffects.get(0));
    }

    @Test
    @DisplayName("测试2: 应用空效果")
    void testApplyNullEffect() {
        effectManager.applyEffect(null);
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(0, activeEffects.size());
    }

    @Test
    @DisplayName("测试3: 应用多个不同类型的效果")
    void testApplyMultipleDifferentEffects() {
        effectManager.applyEffect(testEffect);
        effectManager.applyEffect(testEffect2);
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(2, activeEffects.size());
        assertTrue(activeEffects.contains(testEffect));
        assertTrue(activeEffects.contains(testEffect2));
    }

    @Test
    @DisplayName("测试4: 应用同类型效果（非堆叠）")
    void testApplySameTypeEffect() {
        effectManager.applyEffect(testEffect);
        
        StatusEffect sameTypeEffect = new TestStatusEffect("effect3", StatusType.POWER, mockOwner, 1500, null, 4, 1.3, false, false);
        effectManager.applyEffect(sameTypeEffect);
        
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(1, activeEffects.size(), "非堆叠效果应该被替换而不是新增");
        // 检查效果管理器是否正确记录了最后的效果
        StatusEffect currentEffect = effectManager.getEffect(StatusType.POWER);
        assertNotNull(currentEffect);
        // 应该是第二个效果（新效果）替换了第一个
        assertEquals(StatusType.POWER, currentEffect.getStatusType());
    }

    @Test
    @DisplayName("测试5: 应用堆叠效果")
    void testApplyStackableEffect() {
        TestStatusEffect stackableEffect1 = new TestStatusEffect("effect1", StatusType.POISON, mockOwner, 1000, null, 1, 10.0, true, true);
        TestStatusEffect stackableEffect2 = new TestStatusEffect("effect2", StatusType.POISON, mockOwner, 1000, null, 1, 10.0, true, true);
        
        effectManager.applyEffect(stackableEffect1);
        effectManager.applyEffect(stackableEffect2);
        
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        // 根据StatusEffectManager的shouldStackEffect实现，POISON类型会堆叠
        // 但是根据实际实现，可能不会真正堆叠，而是替换
        assertTrue(activeEffects.size() >= 1, "至少应该有一个效果存在");
        
        // 检查效果管理器是否正确记录了效果
        StatusEffect currentEffect = effectManager.getEffect(StatusType.POISON);
        assertNotNull(currentEffect);
        assertEquals(StatusType.POISON, currentEffect.getStatusType());
    }

    // ========== 效果移除 ==========

    @Test
    @DisplayName("测试6: 移除状态效果")
    void testRemoveEffect() {
        effectManager.applyEffect(testEffect);
        assertEquals(1, effectManager.getActiveEffects().size());
        
        effectManager.removeEffect(testEffect);
        assertEquals(0, effectManager.getActiveEffects().size());
    }

    @Test
    @DisplayName("测试7: 移除不存在的效果")
    void testRemoveNonExistentEffect() {
        effectManager.applyEffect(testEffect);
        StatusEffect nonExistentEffect = new TestStatusEffect("effect99", StatusType.HASTE, mockOwner, 1000, null, 5, 1.5, false, false);
        
        effectManager.removeEffect(nonExistentEffect);
        assertEquals(1, effectManager.getActiveEffects().size());
    }

    @Test
    @DisplayName("测试8: 移除空效果")
    void testRemoveNullEffect() {
        effectManager.applyEffect(testEffect);
        assertEquals(1, effectManager.getActiveEffects().size());
        
        effectManager.removeEffect((StatusEffect)null);
        assertEquals(1, effectManager.getActiveEffects().size());
    }

    @Test
    @DisplayName("测试9: 按类型移除效果")
    void testRemoveEffectsByType() {
        effectManager.applyEffect(testEffect);  // POWER
        effectManager.applyEffect(testEffect2); // FRAGILE
        
        StatusEffect anotherPowerEffect = new TestStatusEffect("effect3", StatusType.POWER, mockOwner, 1500, null, 4, 1.3, false, false);
        effectManager.applyEffect(anotherPowerEffect);
        
        assertEquals(2, effectManager.getActiveEffects().size());
        
        effectManager.removeEffectByType(StatusType.POWER);
        assertEquals(1, effectManager.getActiveEffects().size());
        assertEquals(testEffect2, effectManager.getActiveEffects().get(0));
    }

    // ========== 效果更新和过期 ==========

    @Test
    @DisplayName("测试10: 更新效果（未过期）")
    void testUpdateEffectsNotExpired() {
        effectManager.applyEffect(testEffect);
        effectManager.applyEffect(testEffect2);
        
        // 模拟时间流逝，但不超过效果持续时间
        long currentTime = System.currentTimeMillis();
        effectManager.updateEffects(currentTime, 500);
        
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(2, activeEffects.size());
    }

    @Test
    @DisplayName("测试11: 更新效果（部分过期）")
    void testUpdateEffectsSomeExpired() {
        // 创建一个持续时间很短的效果和一个持续时间较长的效果
        TestStatusEffect shortEffect = new TestStatusEffect("short", StatusType.POWER, mockOwner, 100, null, 1, 1.2, false, false);
        TestStatusEffect longEffect = new TestStatusEffect("long", StatusType.FRAGILE, mockOwner, 5000, null, 1, 0.8, false, false);
        
        effectManager.applyEffect(shortEffect);
        effectManager.applyEffect(longEffect);
        
        // 等待短效果过期
        try {
            Thread.sleep(150);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // 更新效果状态
        long currentTime = System.currentTimeMillis();
        effectManager.updateEffects(currentTime, 200);
        
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        // 至少应该有一个效果存在
        assertTrue(activeEffects.size() >= 1);
        // 长效果应该还存在
        assertTrue(activeEffects.contains(longEffect));
    }

    @Test
    @DisplayName("测试12: 更新效果（全部过期）")
    void testUpdateEffectsAllExpired() {
        // 创建两个持续时间很短的效果
        TestStatusEffect shortEffect1 = new TestStatusEffect("short1", StatusType.POWER, mockOwner, 100, null, 1, 1.2, false, false);
        TestStatusEffect shortEffect2 = new TestStatusEffect("short2", StatusType.FRAGILE, mockOwner, 100, null, 1, 0.8, false, false);
        
        effectManager.applyEffect(shortEffect1);
        effectManager.applyEffect(shortEffect2);
        
        // 等待效果过期
        try {
            Thread.sleep(150);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // 更新效果状态
        long currentTime = System.currentTimeMillis();
        effectManager.updateEffects(currentTime, 200);
        
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        // 效果应该已过期
        assertEquals(0, activeEffects.size());
    }

    // ========== 效果查询 ==========

    @Test
    @DisplayName("测试13: 查询指定类型的效果")
    void testGetEffectsByType() {
        effectManager.applyEffect(testEffect);  // POWER
        
        List<StatusEffect> attackEffects = effectManager.getEffectsByType(StatusType.POWER);
        assertEquals(1, attackEffects.size());
        assertEquals(testEffect, attackEffects.get(0));
        
        List<StatusEffect> defenseEffects = effectManager.getEffectsByType(StatusType.FRAGILE);
        assertEquals(0, defenseEffects.size());
    }

    @Test
    @DisplayName("测试14: 检查是否有指定类型的效果")
    void testHasEffectType() {
        assertFalse(effectManager.hasEffect(StatusType.POWER));
        
        effectManager.applyEffect(testEffect);
        assertTrue(effectManager.hasEffect(StatusType.POWER));
        assertFalse(effectManager.hasEffect(StatusType.FRAGILE));
    }

    @Test
    @DisplayName("测试15: 获取所有活跃效果")
    void testGetActiveEffects() {
        assertEquals(0, effectManager.getActiveEffects().size());
        
        effectManager.applyEffect(testEffect);
        assertEquals(1, effectManager.getActiveEffects().size());
        
        effectManager.applyEffect(testEffect2);
        assertEquals(2, effectManager.getActiveEffects().size());
    }

    @Test
    @DisplayName("测试16: 清除所有效果")
    void testClearAllEffects() {
        effectManager.applyEffect(testEffect);
        effectManager.applyEffect(testEffect2);
        assertEquals(2, effectManager.getActiveEffects().size());
        
        effectManager.clearAllEffects();
        assertEquals(0, effectManager.getActiveEffects().size());
    }

    // ========== 效果属性计算 ==========

    @Test
    @DisplayName("测试17: 计算攻击力修正")
    void testCalculateAttackModifier() {
        effectManager.applyEffect(testEffect); // POWER
        
        // 获取伤害修正值
        double damageModifier = effectManager.getDamageModifier();
        assertEquals(1.5, damageModifier, 0.01f);
        
        // 添加虚弱效果
        StatusEffect weaknessEffect = new TestStatusEffect("weakness", StatusType.WEAKNESS, mockOwner, 2000, null, 1, 1.0, false, false);
        effectManager.applyEffect(weaknessEffect);
        
        // 力量和虚弱同时存在，根据StatusEffectManager的实现会相乘
        damageModifier = effectManager.getDamageModifier();
        assertEquals(0.75, damageModifier, 0.01f); // 1.5 * 0.5 = 0.75
    }

    @Test
    @DisplayName("测试18: 计算防御力修正")
    void testCalculateDefenseModifier() {
        effectManager.applyEffect(testEffect2); // FRAGILE
        
        // 获取防御修正值
        double defenseModifier = effectManager.getDefenseModifier();
        assertEquals(0.7, defenseModifier, 0.01f);
        
        // 添加护盾效果
        StatusEffect shieldEffect = new TestStatusEffect("shield", StatusType.SHIELD, mockOwner, 2000, null, 1, 1.0, false, false);
        effectManager.applyEffect(shieldEffect);
        
        // 脆弱和护盾同时存在，效果可能叠加
        defenseModifier = effectManager.getDefenseModifier();
        assertEquals(1.05, defenseModifier, 0.01f); // 0.7 * 1.5 = 1.05
    }

    @Test
    @DisplayName("测试19: 计算移动速度修正")
    void testCalculateSpeedModifier() {
        // 添加减速效果
        StatusEffect slowEffect = new TestStatusEffect("slow", StatusType.SLOW, mockOwner, 1000, null, 1, 1.0, false, false);
        effectManager.applyEffect(slowEffect);
        
        // 获取移动速度修正值
        double speedModifier = effectManager.getSpeedModifier();
        assertEquals(0.5, speedModifier, 0.01f);
        
        // 添加加速效果
        StatusEffect hasteEffect = new TestStatusEffect("haste", StatusType.HASTE, mockOwner, 1000, null, 1, 1.0, false, false);
        effectManager.applyEffect(hasteEffect);
        
        // 减速和加速同时存在，效果可能叠加
        speedModifier = effectManager.getSpeedModifier();
        assertEquals(0.75, speedModifier, 0.01f); // 0.5 * 1.5 = 0.75
    }

    // ========== 持续伤害效果 ==========

    @Test
    @DisplayName("测试20: 应用持续伤害效果")
    void testApplyPeriodicDamageEffect() {
        TestStatusEffect poisonEffect = new TestStatusEffect("poison", StatusType.POISON, mockOwner, 1000, null, 1, 10.0, true, true);
        effectManager.applyEffect(poisonEffect);
        
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(1, activeEffects.size());
        assertTrue(((TestStatusEffect) activeEffects.get(0)).isPeriodicDamage());
    }

    @Test
    @DisplayName("测试21: 检查持续伤害效果")
    void testCheckPeriodicDamageEffect() {
        TestStatusEffect poisonEffect = new TestStatusEffect("poison", StatusType.POISON, mockOwner, 1000, null, 1, 10.0, true, true);
        effectManager.applyEffect(poisonEffect);
        
        // 检查效果是否活跃
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(1, activeEffects.size());
        
        // 获取伤害值
        TestStatusEffect activePoison = (TestStatusEffect) activeEffects.get(0);
        assertEquals(10.0f, activePoison.getDamageAmount(), 0.01f);
    }

    @Test
    @DisplayName("测试22: 持续伤害效果过期")
    void testExpiredPeriodicDamageEffect() {
        TestStatusEffect poisonEffect = new TestStatusEffect("poison", StatusType.POISON, mockOwner, 100, null, 1, 10.0, true, true);
        effectManager.applyEffect(poisonEffect);
        
        // 等待效果过期
        try {
            Thread.sleep(150);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // 更新效果状态
        long currentTime = System.currentTimeMillis();
        effectManager.updateEffects(currentTime, 50);
        
        // 效果应该已过期
        List<StatusEffect> activeEffects = effectManager.getActiveEffects();
        assertEquals(0, activeEffects.size());
    }

    // ========== 高级功能 ==========

    @Test
    @DisplayName("测试23: 获取效果统计信息")
    void testGetEffectCount() {
        assertEquals(0, effectManager.getEffectCount());
        
        effectManager.applyEffect(testEffect);
        assertEquals(1, effectManager.getEffectCount());
        
        effectManager.applyEffect(testEffect2);
        assertEquals(2, effectManager.getEffectCount());
        
        effectManager.removeEffect(testEffect);
        assertEquals(1, effectManager.getEffectCount());
    }

    @Test
    @DisplayName("测试24: 获取效果摘要信息")
    void testGetEffectsSummary() {
        effectManager.applyEffect(testEffect);
        effectManager.applyEffect(testEffect2);
        
        String summary = effectManager.getEffectsSummary();
        assertNotNull(summary);
        assertTrue(summary.contains("状态效果摘要"));
        assertTrue(summary.contains("POWER") || summary.contains("力量"));
        assertTrue(summary.contains("FRAGILE") || summary.contains("脆弱"));
    }

    @Test
    @DisplayName("测试25: 检查控制状态")
    void testIsControlled() {
        assertFalse(effectManager.isControlled());
        
        // 添加眩晕效果
        StatusEffect stunEffect = new TestStatusEffect("stun", StatusType.STUN, mockOwner, 1000, null, 1, 1.0, false, false);
        effectManager.applyEffect(stunEffect);
        
        assertTrue(effectManager.isControlled());
        assertTrue(effectManager.isStunned());
        
        // 移除眩晕效果
        effectManager.removeEffect(stunEffect);
        assertFalse(effectManager.isControlled());
        assertFalse(effectManager.isStunned());
    }
}